<?php


namespace Um\WechatPay\V3Api;

use Ke\Helper\DateRangeHelper;
use Um\WechatPay\PayException;
use Um\WechatPay\PayV3Status;

/**
 * 微信商户 V3 代金券接口
 *
 * Coupon or Voucher
 * - Voucher通常给顾客一个“一次性”的优惠，一般来说按照结账的总金额给出一定的折扣价
 * - 一张（或一个）Voucher通常只能使用一次
 * - Coupon一般都只需要在结账的时候出示即可，可以多次使用，直到有效期结束
 * - Coupon通常用纸质小广告或是电子邮件的形式给予顾客（例如在大街上发送给您或是直接放到您家的邮箱里）
 * - Voucher，一般会有一个ID或是号码印刷在上面，消费后这个ID就会失效
 * - Voucher 一般是您消费在先才能获得下一次优惠的机会，而Coupon往往不需要消费就会以“广而告之”的形式发送到您的手中
 *
 * @package Um\WechatPay
 */
class VoucherApi extends V3ApiCore
{

	const STATUS_UNACTIVE = 'unactivated';
	const STATUS_AUDIT    = 'audit';
	const STATUS_RUNNING  = 'running';
	const STATUS_STOP     = 'stoped';
	const STATUS_PAUSE    = 'paused';

	/**
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_4.shtml
	 *
	 * @param int                  $offset
	 * @param int                  $limit
	 * @param string               $status
	 * @param DateRangeHelper|null $range
	 * @param string|null          $merchantId
	 *
	 * @return \Um\WechatPay\PayV3Status
	 * @throws \Exception
	 */
	public function getVouchers(
		int $offset = 0,
		int $limit = 10,
		string $status = self::STATUS_RUNNING,
		DateRangeHelper $range = null,
		string $merchantId = null)
	{
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		if ($limit > 10) $limit = 10;
		elseif ($limit <= 1) $limit = 1;
		$req = $this->newRequest('https://api.mch.weixin.qq.com/v3/marketing/favor/stocks');
		// required data
		$data = [
			'offset'              => $offset,
			'limit'               => $limit,
			'stock_creator_mchid' => $merchantId,
		];
		if (!empty($status))
			$data['status'] = $status;
		if (isset($range)) {
			$data['create_start_time'] = $range->start()->format('c');
			$data['create_end_time'] = $range->start()->format('c');
		}
		$st = $this->filterResponse($req->get($data));
		// 这个接口成功返回的内容是：
		// {data: [{...}, {...}]} 这个格式
		// 如果不过滤输出的话，就会 $st->data['data'] ，非常的繁琐，所以这里直接把 $st->data 替换成 $st->data['data']
		// 拿到这个结果，只要判定 $st->isSuccess() 直接循环 $st->data 即可
		$st->data = $st->data['data'] ?? [];
		return $st;
	}

	/**
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_5.shtml
	 *
	 * @param string      $stockId
	 * @param string|null $merchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function getVoucher(string $stockId, string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$stockId}")->get([
			'stock_creator_mchid' => $merchantId,
		]);
		return $this->filterResponse($req);
	}

	/**
	 * 通过API发放的支付代金券，不能马上放入用户的卡包中。
	 * 有个专门的放入卡包的API接口，在H5页面中实现。
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_2.shtml
	 *
	 * @param string      $stockId
	 * @param string      $openId
	 * @param string|null $merchantAppId
	 * @param string      $outRequestNo
	 * @param int         $couponValue
	 * @param int         $couponMinimum
	 * @param string|null $merchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function giveVoucher(
		string $stockId,
		string $openId,
		string $socialAppId,
		string $outRequestNo,
		int $couponValue = 0,
		int $couponMinimum = 0,
		string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($openId))
			throw new PayException('未指定有效的用户openid');
		if (empty($outRequestNo))
			throw new PayException('未指定有效的商户单据号');
		if (empty($socialAppId))
			throw new PayException('未指定有效的公众号AppId');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();

		$data = [
			'stock_id'            => $stockId,
			'out_request_no'      => $outRequestNo,
			'appid'               => $socialAppId,
			'stock_creator_mchid' => $merchantId,
		];
		if (!empty($couponValue))
			$data['coupon_value'] = $couponValue;
		if (!empty($couponMinimum))
			$data['coupon_minimum'] = $couponMinimum;
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/users/{$openId}/coupons")->post($data);
		return $this->filterResponse($req);
	}

	/**
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_6.shtml
	 *
	 * @param string $couponId
	 * @param string $openId
	 * @param string $socialAppId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function getUserVoucher(string $couponId, string $openId, string $socialAppId)
	{
		if (empty($couponId))
			throw new PayException('未指定有效的代金券id（couponId）');
		if (empty($openId))
			throw new PayException('未指定有效的用户openid');
		if (empty($socialAppId))
			throw new PayException('未指定有效的公众号AppId');
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/users/{$openId}/coupons/{$couponId}")->get([
			'appid' => $socialAppId,
		]);
		return $this->filterResponse($req);
	}

	const USE_STATUS_SENDED = 'SENDED'; //可用
	const USE_STATUS_USED   = 'USED'; //已实扣

	/**
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_9.shtml
	 *
	 * @param string      $openId
	 * @param string      $socialAppId
	 * @param string|null $stockId
	 * @param string|null $status //USE_STATUS_SENDED || USE_STATUS_USED
	 * @param int         $offset
	 * @param int         $limit
	 * @param string|null $creatorMerchantId
	 * @param string|null $senderMerchantId
	 * @param string|null $availableMerchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function getUserVouchers(
		string $openId,
		string $socialAppId,
		string $stockId = null,
		string $status = null,
		int $offset = 0,
		int $limit = 10,
		string $creatorMerchantId = null,
		string $senderMerchantId = null,
		string $availableMerchantId = null)
	{
		if (empty($openId))
			throw new PayException('未指定有效的用户openid');
		if (empty($socialAppId))
			throw new PayException('未指定有效的公众号AppId');

		if ($limit > 10) $limit = 10;
		elseif ($limit <= 1) $limit = 1;

		if (empty($creatorMerchantId)) $creatorMerchantId = $this->masterApi->getMerchantId();

		$data = [
			'appid'         => $socialAppId,
			'creator_mchid' => $creatorMerchantId,
			'offset'        => $offset,
			'limit'         => $limit,
		];
		if (!empty($status))
			$data['status'] = $status;
		//如果指定批次号查询，但又填写了available_mchid，则stock_id字段不生效。
		if (!empty($stockId))
			$data['stock_id'] = $stockId;
		if (!empty($senderMerchantId))
			$data['sender_mchid'] = $senderMerchantId;
		if (!empty($availableMerchantId))
			$data['available_mchid'] = $availableMerchantId;

		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/users/{$openId}/coupons")->get($data);
		$st = $this->filterResponse($req);
//		$st->data = $st->data['data'] ?? [];
		return $st;
	}

	/**
	 *
	 * @see  https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_7.shtml
	 *
	 * @param string      $stockId
	 * @param int         $offset
	 * @param int         $limit
	 * @param string|null $merchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function getVoucherMerchants(
		string $stockId,
		int $offset = 0,
		int $limit = 10,
		string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		if ($limit > 10) $limit = 10;
		elseif ($limit <= 1) $limit = 1;
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$stockId}/merchants")->get([
			'offset'              => $offset,
			'limit'               => $limit,
			'stock_creator_mchid' => $merchantId,
		]);
		$st = $this->filterResponse($req);
		$st->data = $st->data['data'] ?? [];
		return $st;
	}

	/**
	 * 制券成功后，通过调用此接口激活批次，如果是预充值代金券，激活时会从商户账户余额中锁定本批次的营销资金。
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_3.shtml
	 * @param string      $stockId
	 * @param string|null $merchantId
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function startVoucher(string $stockId, string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$stockId}/start")->post([
			'stock_creator_mchid' => $merchantId,
		]);
		$st = $this->filterResponse($req);
		return $st;
	}

	/**
	 * 创建代金券
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_1.shtml
	 * @param array $data
	 *
	 * @return PayV3Status
	 * @throws \Exception
	 */
	public function createVoucher(array $data)
	{
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/coupon-stocks")->post($data);
		$st = $this->filterResponse($req);
		return $st;
	}

	/**
	 * 暂停代金券
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_13.shtml
	 * @param string      $stockId
	 * @param string|null $merchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function pauseVoucher(string $stockId, string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$stockId}/pause")->post([
			'stock_creator_mchid' => $merchantId,
		]);
		$st = $this->filterResponse($req);
		return $st;
	}

	/**
	 * 重启代金券
	 *
	 * @see https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/convention/chapter3_14.shtml
	 * @param string      $stockId
	 * @param string|null $merchantId
	 *
	 * @return PayV3Status
	 * @throws PayException
	 */
	public function restartVoucher(string $stockId, string $merchantId = null)
	{
		if (empty($stockId))
			throw new PayException('未指定有效的代金券批次号');
		if (empty($merchantId)) $merchantId = $this->masterApi->getMerchantId();
		$req = $this->newRequest("https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$stockId}/restart")->post([
			'stock_creator_mchid' => $merchantId,
		]);
		$st = $this->filterResponse($req);
		return $st;
	}
}